package com.hsurosy.hsuchain.nft.web.filter;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.redisson.api.RScript;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Arrays;

/**
 * Token过滤器
 *
 * @Author Hsu琛君珩
 * @Date 2024-10-05 5:13
 * @Description
 * @Version: v1.0.0
 */
public class TokenFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(TokenFilter.class);

    /**
     * 用于存储Token的ThreadLocal
     */
    public static final ThreadLocal<String> tokenThreadLocal = new ThreadLocal<>();

    /**
     * Redisson客户端，用于与Redis进行交互
     */
    private RedissonClient redissonClient;

    /**
     * 构造函数，初始化Redisson客户端
     *
     * @param redissonClient Redisson客户端
     */
    public TokenFilter(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 过滤器初始化方法（可选实现）
     *
     * @param filterConfig 过滤器配置
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 过滤器初始化，可根据需要添加实现
    }

    /**
     * 过滤器核心方法，执行Token验证
     *
     * @param request  Servlet请求对象
     * @param response Servlet响应对象
     * @param chain    过滤器链
     * @throws IOException      IO异常
     * @throws ServletException Servlet异常
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;

            // 从请求头中获取Token
            String token = httpRequest.getHeader("Authorization");

            // 如果Token为空或无效，返回401未授权
            if (token == null || "null".equals(token) || "undefined".equals(token)) {
                httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                httpResponse.getWriter().write("No Token Found ...");
                logger.error("No token found in header, please check!");
                return;
            }

            // 校验Token的有效性
            boolean isValid = checkTokenValidity(token);

            // 如果Token无效或过期，返回401未授权
            if (!isValid) {
                httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                httpResponse.getWriter().write("Invalid or expired token");
                logger.error("Token validation failed, please check!");
                return;
            }

            // 如果Token有效，继续执行其他过滤器链
            chain.doFilter(request, response);
        } finally {
            // 清除ThreadLocal中的Token
            tokenThreadLocal.remove();
        }
    }

    /**
     * 校验Token的有效性
     *
     * @param token 要校验的Token
     * @return true如果Token有效，false否则
     */
    private boolean checkTokenValidity(String token) {
        String luaScript = """
                local value = redis.call('GET', KEYS[1])
                redis.call('DEL', KEYS[1])
                return value""";

        // 使用Lua脚本从Redis中获取并删除Token
        String result = (String) redissonClient.getScript().eval(RScript.Mode.READ_WRITE,
                luaScript,
                RScript.ReturnType.STATUS,
                Arrays.asList(token));

        // 将Token信息存储到ThreadLocal中
        tokenThreadLocal.set(result);
        return result != null;
    }

    /**
     * 过滤器销毁方法（可选实现）
     */
    @Override
    public void destroy() {
        // 销毁过滤器，可根据需要添加实现
    }
}
